package cn.funeralobjects.upms.service.impl;

import cn.funeralobjects.common.jpa.service.CommonCloudCrudJpaService;
import cn.funeralobjects.common.repository.CommonCloudRepository;
import cn.funeralobjects.common.service.annotataion.CommonRollback;
import cn.funeralobjects.common.service.annotataion.CommonService;
import cn.funeralobjects.common.service.exception.DataConflictException;
import cn.funeralobjects.common.service.validate.DataCheck;
import cn.funeralobjects.upms.entity.ELoginUser;
import cn.funeralobjects.upms.entity.QELoginUser;
import cn.funeralobjects.upms.model.LoginUser;
import cn.funeralobjects.upms.repository.LoginUserRepository;
import cn.funeralobjects.upms.service.LoginUserService;
import cn.funeralobjects.util.Assert;
import cn.funeralobjects.util.annotation.ArgHasLength;
import cn.funeralobjects.util.annotation.ArgNotEmpty;
import cn.funeralobjects.util.annotation.ArgNotZero;
import cn.funeralobjects.util.annotation.AssertArg;
import com.querydsl.jpa.JPQLQueryFactory;
import org.springframework.data.repository.CrudRepository;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * LoginUserService的实现
 *
 * @author FuneralObjects
 * Create date: 2020/4/22 9:50 AM
 */
@CommonService
public class LoginUserServiceImpl implements LoginUserService, CommonCloudCrudJpaService<LoginUser, ELoginUser, Integer> {

    @Resource
    private LoginUserRepository loginUserRepository;


    @Resource
    private JPQLQueryFactory jpqlQueryFactory;

    @CommonRollback
    @AssertArg
    @Override
    public void deleteByNameFromUser(Integer userId, String name) {
        findLoginUserByName(name).ifPresentOrElse(
                loginUser -> {
                    DataCheck.dataMismatch(!loginUser.getUserId().equals(userId), () -> createDataCode("name", name), () -> createDataCode("userId", String.valueOf(userId)));
                    loginUserRepository.delete(loginUser);
                },
                () -> DataCheck.lackData(true, () -> createDataCode("name", name))
        );
    }

    @CommonRollback
    @Override
    public void deleteAllByUser(Integer userId) {
        loginUserRepository.findAllByUserIdAndDelSalt(userId, getExistsDelSalt())
                .stream()
                .map(ELoginUser::getId)
                .forEach(loginUserRepository::deleteById);
    }

    @AssertArg
    @Override
    public Integer findUserIdByNameAndPassword(@ArgHasLength String name, @ArgHasLength String password) {
        return jpqlQueryFactory.select(QELoginUser.eLoginUser.userId)
                .from(QELoginUser.eLoginUser)
                .where(QELoginUser.eLoginUser.name.eq(name).and(QELoginUser.eLoginUser.password.eq(password)).and(QELoginUser.eLoginUser.delSalt.eq(getExistsDelSalt())))
                .fetchOne();
    }

    @AssertArg
    @Override
    public Optional<ELoginUser> findLoginUserByName(@ArgHasLength String name) {
        return loginUserRepository.findByNameAndDelSalt(name, getExistsDelSalt());
    }

    @AssertArg
    @Override
    public List<ELoginUser> findAllByUserId(@ArgNotZero Integer userId) {
        return loginUserRepository.findAllByUserIdAndDelSalt(userId, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void disable(@ArgHasLength String name) {
        mustExistsName(name);
        loginUserRepository.updateEnableByNameInAndDelSalt(false, name, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void enable(@ArgHasLength String name) {
        mustExistsName(name);
        loginUserRepository.updateEnableByNameInAndDelSalt(true, name, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void disable(@ArgNotZero Integer userId) {
        loginUserRepository.updateEnableByUserIdInAndDelSalt(false, userId, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void disable(@ArgNotEmpty List<Integer> userIds) {
        loginUserRepository.updateEnableByUserIdsInAndDelSalt(false, userIds, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void enable(@ArgNotZero Integer userId) {
        loginUserRepository.updateEnableByUserIdInAndDelSalt(true, userId, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void enable(@ArgNotEmpty List<Integer> userIds) {
        loginUserRepository.updateEnableByUserIdsInAndDelSalt(true, userIds, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void updatePassword(@ArgHasLength String name, @ArgHasLength String password) {
        mustExistsName(name);
        loginUserRepository.updatePasswordByNameAndDelSalt(password, name, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void updatePassword(@ArgNotEmpty Map<String, String> namePasswordMap) {
        namePasswordMap.entrySet().parallelStream().forEach(e -> loginUserRepository.updatePasswordByNameAndDelSalt(e.getValue(), e.getKey(), getExistsDelSalt()));
    }

    @Override
    public void mustExistsName(String name) {
        DataCheck.conflictData(!existsByName(name), () -> createDataCode("name", name));
    }

    private Integer getExistsDelSalt() {
        return (Integer) loginUserRepository.getDefaultExistsDelSalt();
    }

    @Override
    public CommonCloudRepository<ELoginUser, Integer> commonCloudRepository() {
        return loginUserRepository;
    }

    @Override
    public void checkConflict(LoginUser loginUser) throws DataConflictException {
        validateModify(loginUser);
        mustNotConflictByName(loginUser.getName());
    }

    @Override
    public ELoginUser toEntity(LoginUser loginUser) {
        return Optional.ofNullable(loginUser)
                .map(modify -> {
                    ELoginUser entity = new ELoginUser();
                    this.copyToEntity(modify, entity);
                    return entity;
                }).orElse(null);
    }

    @Override
    public CrudRepository<ELoginUser, Integer> modifyRepository() {
        return loginUserRepository;
    }

    @Override
    public void checkConflict(LoginUser loginUser, Integer withoutId) throws DataConflictException {
        validateModify(loginUser);
        mustNotConflictByName(loginUser.getName(), withoutId);
    }

    @Override
    public void copyToEntity(LoginUser sourceModify, ELoginUser targetEntity) {
        targetEntity.setUserId(sourceModify.getUserId())
                .setPassword(sourceModify.getPassword())
                .setName(sourceModify.getName())
                .setCode(sourceModify.getCode());
    }

    @Override
    public void validateModify(LoginUser loginUser) {
        Assert.argAssert(loginUser, "loginUser");
    }
}
